/*
 * @project java-awesome-examples
 * @file    PACKAGE_NAME.GraalJSTest
 * CREATE   2025年08月13日 15:47 下午
 * --------------------------------------------------------------
 * 0604hx   https://github.com/0604hx
 * --------------------------------------------------------------
 */

import org.graalvm.polyglot.Context;
import org.graalvm.polyglot.HostAccess;
import org.graalvm.polyglot.Value;
import org.junit.jupiter.api.Test;

import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.Map;
import java.util.UUID;

public class GraalJSTest {

    public static String JS = "js";

    private void printValue(Value value){
        System.out.printf("%n------------------------ 脚本返回值 ------------------------%n%s", value);
    }

    @Test
    public void hello(){
        try(Context context = Context.create(JS)){
            context.eval(JS,"console.log(`来自 GraalJS 的问候！Time=${Date.now()}`)");
        }
    }

    /**
     * 构建一个 JS 函数，支持传递参数并得到结果
     */
    @Test
    public void funWithParams(){
        try(Context ctx = Context.create(JS)){
            Value addFunc = ctx.eval(JS, "(x, y)=> x+y");
            //调用函数
            int result = addFunc.execute(100, 100).asInt();

            System.out.println("执行 100+100 函数，结果="+result);
        }
    }

    public class JavaLogger {
        // 定义时间格式器（HH表示24小时制，hh表示12小时制）
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm");

        private void log(String level, String msg){
            String time = LocalTime.now().format(formatter);
            System.out.printf("[JAVA] %s %-5s %s%n", time, level, msg);
        }

        public void info(String msg){ log("INFO", msg); }

        public void debug(String msg){ log("DEBUG", msg); }

        public void error(String msg){ log("ERROR", msg); }
    }

/**
 * 设置全局变量
 */
@Test
public void bindings(){

    /**
     * 自定义 Java 、JS 互通规则，按需开启对应的权限
     * 参数定义规则：https://www.graalvm.org/truffle/javadoc/org/graalvm/polyglot/HostAccess.Builder.html#targetTypeMapping-java.lang.Class-java.lang.Class-java.util.function.Predicate-java.util.function.Function-
     */
    HostAccess hostAccess = HostAccess.newBuilder()
            //允许不受限制地访问所有公共构造函数、公共类的方法或字段
            .allowPublicAccess(true)
            //允许客户端语言实现任何 Java 接口
            .allowAllImplementations(false)
            //允许客户端语言实现（扩展）任何 Java 类
            .allowAllClassImplementations(false)
            //允许访问数组
            .allowArrayAccess(false)
            //允许访问 List
            .allowListAccess(false)
            //允许客户应用程序以缓冲区元素的形式访问 ByteBuffers
            .allowBufferAccess(false)
            //允许客户应用程序使用迭代器将可迭代对象作为值进行访问
            .allowIterableAccess(false)
            //允许客户应用程序将迭代器作为迭代器值进行访问。
            .allowIteratorAccess(false)
            //允许客户应用程序以哈希值形式访问 Map 对象
            .allowMapAccess(true)
            //允许客户应用程序继承对允许方法的访问权限
            .allowAccessInheritance(false)
            .build();

    // 使用自定义 HostAccess 构建 Context
    try(Context ctx=Context.newBuilder(JS).allowHostAccess(hostAccess).build()){

        Value global =  ctx.getBindings(JS);
        global.putMember("UUID", UUID.randomUUID().toString());
        // 传递 Map 键值对
        global.putMember(
                "User",
                Map.of(
                "name", "集成显卡",
                        "url", "https://github.com/0604hx"
                )
        );
        // 放置对象示例
        global.putMember("log", new JavaLogger());

        String script = """
            log.info(`开始执行 JS 脚本，UUID=${UUID}`)
            log.debug(`测试 debug 日志...`)
            log.error(`测试 error 日志...`)

            let result = { time: Date.now(), name: User.name, uuid: UUID }
            result
            """;
        printValue(ctx.eval(JS, script));
    }
}
}
